#include "book-convert.h"

#include <stdint.h>

#include <fstream>
#include <sstream>
#include <algorithm>

#include "util/logger/logger.h"
#include "util/strutil.h"
#include "util/fs-util.h"

#include "markdown/article-convert.h"
#include "chapter-menu-convert.h"


static std::string makeTitle(const fs::path &srcdir) {
    std::ostringstream ss;
    ss << "BookConvert(" << fs::absolute(srcdir).lexically_normal().generic_string() << ") ";
    return ss.str();
}

namespace book
{

BookConvert::BookConvert(const fs::path &srcdir, const fs::path &destdir)
    : title_(makeTitle(srcdir))
    , route_(srcdir, destdir)
    , bookMenuConvert_(route_.dest()) {

    LOGD << title() << "construct, srcdir: [" << route_.src() << "], destdir: [" << route_.dest() << "]";

    if (!fs::is_directory(route_.src())) {
        throw DirCheckError("srcdir is not directory");
    }

    if (!fs::is_directory(route_.dest())) {
        throw DirCheckError("destdir is not directory");
    }

    if (fsutil::isUpperThan(srcdir, destdir)) {
        throw DirCheckError("destdir cannot be in srcdir");
    }

    if (fsutil::isSamePath(srcdir, destdir)) {
        throw DirCheckError("destdir cannot be the same dir to srcdir");
    }
}

Book BookConvert::operator()() {
    IndexTree indexTree(route_.src());
    UriPath uri;
    handleDir(indexTree.root(), route_, uri);
    Book book;
    book.setSrcDir(route_.src());
    book.setIndexTree(std::move(indexTree));
    book.setGeneratedDir(route_.dest());
    return book;
}

void BookConvert::handleDir(const IndexTree::Node *node, const ConvertRoute &route, UriPath &uri) {

    if (!node) {
        assert(false && "IndexTree never contains null Node pointer");
        return;
    }

    LOGD << title() << "handleDir: [" << route.src() << "]";

    fs::create_directories(route.dest());

    const std::string chapterMenuFilePath = route.dest("a.chaptermenu.html").generic_string();
    std::ofstream chapterMenuFile(chapterMenuFilePath, std::ios::binary);
    ChapterMenuConvert chapterMenuConvert(chapterMenuFile);

    for (const IndexTree::Node *child : node->children()) {
        const IndexItem &item = child->data();
        const UriPath::PushPopScope uriScope(uri, item.uriName());
        if (fs::is_directory(route.src(item.dirEntryName()))) {
            const BookMenuConvert::ChapterScope chapterScope(bookMenuConvert_, uri, item);
            const ConvertRoute subRoute(route, item.dirEntryName(), item.uriName());
            handleDir(child, subRoute, uri);
        } else {
            bookMenuConvert_.notifyMeetArticle(uri, item);
            ArticleConvert articleConvert(route, item);
            articleConvert();
        }

        chapterMenuConvert.feed(uri, item);
    }

}

} // namespace book

